package org.apache.hop.pipeline.transforms.script;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.Reader;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
import javax.script.AbstractScriptEngine;
import javax.script.Bindings;
import javax.script.ScriptContext;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineFactory;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import javax.script.SimpleBindings;
import org.apache.hop.core.Const;
import org.apache.hop.core.row.IRowMeta;
import org.apache.hop.core.row.RowDataUtil;
import org.json.JSONObject;

public class ShellScriptEngine extends AbstractScriptEngine {
  public String cmd_type = "cpython";

  // add by bzm
  private String executePythonScript(String cmd, String scriptPath) throws Exception {
    // List<String> command = Arrays.asList("python", scriptPath);
    List<String> command = Arrays.asList(cmd, scriptPath);
    ProcessBuilder processBuilder = new ProcessBuilder(command);
    processBuilder.redirectErrorStream(true);

    Process process = processBuilder.start();
    // 读取标准输出流
    BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
    StringBuilder output = new StringBuilder();
    String line;
    while ((line = reader.readLine()) != null) {
      output.append(line).append("\n");
    }
    System.out.println("output:" + output);
    // 等待Python进程结束
    int exitCode = process.waitFor();
    if (exitCode == 0) {
      return output.toString();
    }
    return "";
  }

  @Override
  public Object eval(String script, Bindings bindings) throws ScriptException {
    // 将bindings中的参数替换到脚本中
    IRowMeta input = (IRowMeta) bindings.get("rowMeta");
    int szInput = input.size();
    StringBuilder param = new StringBuilder();
    for (int i = 0; i < szInput; i++) {
      String key = input.getValueMeta(i).getName();
      Object val = bindings.get(key);
      if (val == null) continue;
      // 字符串
      if (cmd_type.equals("shell")) {
        // 可以添加多行字符串
        param
            .append(key)
            .append(" =$(cat <<EOF")
            .append("\r\n")
            .append(val)
            .append("\r\n")
            .append("EOF")
            .append("\r\n")
            .append(")")
            .append("\r\n");
      } else {
        if (input.getValueMeta(i).getType() == 2) {
          param.append(key).append(" = '''").append(val).append("'''\r\n");
        } else {
          param.append(key).append(" = ").append(val).append("\r\n");
        }
      }
    }
    //    for (String key : bindings.keySet()) {
    //      System.out.println("[bzm]kye="+key);
    //    }
    script = param + script;
    // add by bzm
    // 1. 生成随机文件名
    String cmd = "python";
    String fileName = "py" + UUID.randomUUID();
    if (cmd_type.equals("shell")) {
      fileName += ".sh";
      cmd = "bash";
    } else {
      fileName += ".py";
    }
    // 替换script里面的${PROJECT_HOME}目录
    String prjDir = Const.HOP_CONFIG_FOLDER + "/projects/samples";
    script = script.replaceAll("\\$\\{PROJECT_HOME\\}", prjDir);
    // 2. 将Python字符串写入到临时目录中的文件
    Path tempFile;
    try {
      tempFile =
          Files.write(
              Paths.get(System.getProperty("java.io.tmpdir"), fileName),
              script.getBytes(StandardCharsets.UTF_8));
      // 3. 运行Python文件
      String ret = executePythonScript(cmd, tempFile.toString());
      System.out.println("[bzm]: eval- ret=" + ret);
      IRowMeta out = (IRowMeta) bindings.get("outputRowMeta");
      if (szInput == 0) return ret;
      Object[] outObj = RowDataUtil.allocateRowData(szInput);
      JSONObject jsonObject;
      try {
        jsonObject = new JSONObject(ret);
        // 必须要加一个result输入参数，不然没有参数输出
        for (int i = 0; i < szInput; i++) {
          String key = input.getValueMeta(i).getName();
          int type = input.getValueMeta(i).getType();
          System.out.println("[bzm]type" + type);
          Object val =
              switch (type) {
                case 2 -> jsonObject.getString(key);
                case 5 -> jsonObject.getInt(key);
                default -> "";
              };
          outObj[i] = val;
        }
      } catch (Exception e) {
        e.printStackTrace();
      }
      Script sc = (Script) bindings.get("transform");
      sc.putRow(out, outObj);
      return ret;
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
  }

  @Override
  public Object eval(String script, ScriptContext context) throws ScriptException {
    throw new UnsupportedOperationException();
  }

  @Override
  public Object eval(Reader reader, ScriptContext context) throws ScriptException {
    throw new UnsupportedOperationException();
  }

  @Override
  public Bindings createBindings() {
    return new SimpleBindings();
  }

  @Override
  public ScriptEngineFactory getFactory() {
    return new ShellScriptEngineFactory();
  }

  public class Main {
    public static void main(String[] args) {
      ScriptEngineManager manager = new ScriptEngineManager();
      ScriptEngine engine = manager.getEngineByName("cpython");

      if (engine == null) {
        System.err.println("Shell script engine not found.");
        return;
      }

      try {
        String script = "echo Hello, World!";
        String result = (String) engine.eval(script);
        System.out.println("Script Output: " + result);
      } catch (ScriptException e) {
        e.printStackTrace();
      }
    }
  }
}
